package cn.itcast.service.impl;

import cn.itcast.dtos.ChatDTO;
import cn.itcast.service.ChatService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.chat.client.advisor.AbstractChatMemoryAdvisor;
import org.springframework.ai.chat.client.advisor.QuestionAnswerAdvisor;
import org.springframework.ai.vectorstore.SearchRequest;
import org.springframework.ai.vectorstore.VectorStore;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

/**
 * @Author:篍
 * @Date: 2025/10/11 9:55
 * @Description:
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class ChatServiceImpl implements ChatService {

    private final ChatClient chatClient;

    private final VectorStore vectorStore;

    /**
     * @param chatDTO 用户提问dto
     * @return ai回复
     */
    @Override
    public String chat(ChatDTO chatDTO) {

        // 创建搜索请求，用于搜索相关文档
        var searchRequest = SearchRequest.builder()
                .query(chatDTO.getQuestion()) // 设置查询条件
                .topK(2) // 设置最多返回的文档数量
                .build();


        return chatClient.prompt()
                .user(chatDTO.getQuestion())
                // 设置会话id
                .advisors(advisor-> advisor.advisors(new QuestionAnswerAdvisor(vectorStore,searchRequest))
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY,chatDTO.getSessionId()))
                .call()
                .content();

    }

    /**
     * 处理用户问题并返回流式响应内容
     * @param chatDTO 用户提问dto
     * @return 包含逐条响应内容和结束标记的响应流，每个元素为字符串格式
     */
    @Override
    public Flux<String> streamChat(ChatDTO chatDTO) {
        // 创建搜索请求，用于搜索相关文档
        var searchRequest = SearchRequest.builder()
                .query(chatDTO.getQuestion()) // 设置查询条件
                .topK(2) // 设置最多返回的文档数量
                .build();

        // 调用聊天客户端生成流式响应内容
        return this.chatClient.prompt()
                .user(chatDTO.getQuestion())
                // 设置会话id
                .advisors(advisor-> advisor.advisors(new QuestionAnswerAdvisor(vectorStore,searchRequest))
                        .param(AbstractChatMemoryAdvisor.CHAT_MEMORY_CONVERSATION_ID_KEY,chatDTO.getSessionId()))
                .stream()
                .content()
                // 记录每次接收到的响应内容
                .doOnNext(content -> log.info("question: {}, content: {}", chatDTO.getQuestion(), content))
                // 在流结束时添加结束标记
                .concatWith(Flux.just("[END]"));
    }
}
